<!--
 * @Descripttion: 
 * @Author: 银河以北
 * @Date: 2023-03-01 21:43:52
 * @LastEditors: 银河以北
 * @LastEditTime: 2023-04-22 21:51:04
-->
<template>
    <div class="app-container">

        <div class="container" ref="container">
            <div class="item" v-for="(item, index) in imgList" :key="index" :style="{
            backgroundColor: randomRGB()
          }">
                <img :src="item.url" :alt="item.url" />
            </div>

            <!-- <div class="loding" v-if="isLoding">loding xxx</div> -->
            <el-dialog v-model="isLoding" width="30%" :show-close="false">
                图片资源加载中....
            </el-dialog>
        </div>

    </div>
</template>
<script setup>
    import {
        randomRGB
    } from '@/utils/utils'
    import {
        ref,
        reactive,
        watch,
        computed
    } from 'vue';

    import {
        set,
        useWindowScroll
    } from '@vueuse/core'

    import {
        ElMessage
    } from 'element-plus'




    const {
        x,
        y
    } = useWindowScroll()

    const props = defineProps({
        // 盒子宽度
        boxWidth: {
            type: Number,
            required: true
        },

        // 列间隙
        colInterval: {
            type: Number,
            default: 0
        },

        // 列数
        colNum: {
            type: Number,
            default: 5
        }

    })


    // 判断是否在在加载
    let isLoding = ref(false)


    // 记录加载数量
    let loadedCount = 0

    // total
    let total = 0

    // 真实渲染的图片数据
    let imgList = reactive([])

    // 所有图片盒子
    let imgBoxList = []


    // 最外层容器宽度
    const waterfallWidth = props.boxWidth
    const waterfallWidthPx = computed(() => {
        return props.boxWidth + 'px'
    })

    // 每一列宽度
    const colWidth = computed(() => {
        return Math.floor((props.boxWidth - (props.colNum - 1) * props.colInterval) / props.colNum)
    })
    const colWidthPx = computed(() => {
        return Math.floor((props.boxWidth - (props.colNum - 1) * props.colInterval) / props.colNum) + 'px'
    })


    // 每一列的高度
    let colsHeightArr = []

    // 开始排列的坐标
    let beginIndex = 0



    // 处理图片
    const handle = (list) => {
        // promise 集合
        const promiseAll = []

        list.forEach((item, index) => {


            // 如果图片不存在
            if (!item.url) {
                item._height = '0'
                loadedCount++
                console.log('加载错误')
                if (loadedCount == total) {
                    imgList.push(...list)
                }
            }

            // 把每张图图片都加入promise队列，在所有图片加载完后再进行渲染
            const itemPromise = new Promise((resolve, reject) => {
                let Img = new Image()
                Img.src = item.url
                Img.onload = Img.onerror = (e) => {

                    if (e.type == 'load') {
                        item._height = Img.height / Img.width * colWidth.value
                        item._error = false
                    }

                    if (e.type == 'error') {
                        item._error = true
                        // Img.src='https://vue-cdn.oss-cn-hangzhou.aliyuncs.com/error.png'
                        // item.url='https://vue-cdn.oss-cn-hangzhou.aliyuncs.com/error.png'
                        item._height = 200
                    }
                    loadedCount++

                    if (loadedCount == total) {
                        imgList.push(...list)
                        console.log('预加载成功')
                    }

                    // console.log(index,'index')
                    resolve({
                        index
                    })
                }
            })

            promiseAll.push(itemPromise)

        })

        return Promise.all(promiseAll)


    }

    //排列函数
    const waterfalll = (list) => {

        // 获取所有图片item
        imgBoxList = document.getElementsByClassName('item')

        if (imgBoxList.length == 0) return

        // 元素 顶部距离 左边距离 自身高度  宽度（每一列的宽度）
        let top, left, height, colWidths = colWidth.value;

        if (beginIndex == 0) colsHeightArr = []

        for (let i = beginIndex; i < imgList.length; i++) {

            if (!imgBoxList[i]) return

            // 获取渲染元素的高
            height = imgList[i]._height
            if (i < props.colNum) {
                colsHeightArr.push(height)
                top = 0;
                left = i * colWidths + i * props.colInterval

            } else {
                let minHeight = Math.min(...colsHeightArr)
                let minIndex = colsHeightArr.indexOf(minHeight)

                colsHeightArr[minIndex] = height + minHeight
                top = minHeight.toFixed(0)
                left = minIndex * colWidths + minIndex * props.colInterval
            }


            imgBoxList[i].style.left = left + 'px'
            imgBoxList[i].style.top = top + 'px'

            beginIndex++

        }

        // 判断第一次加载是否大于屏幕高度，如果再次加载
        if (Math.min(...colsHeightArr) < document.documentElement.clientHeight) {
            init()
        }

    }

    // 模拟获取数据
    const getData = () => {
        // 1234模拟图片请求失败
        let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
        let list = []
        for (let i = 0; i < 15; i++) {
            let num = arr[Math.floor((Math.random() * arr.length))];
            list.push({
                url: 'https://yinheyibei.oss-cn-beijing.aliyuncs.com/test/img/img/' + num + '.png'
            })
        }
        total += 15
        return list
    }

    // const test = () => {
    //     console.log(ElMessage)
    //     ElMessage.success({
    //         message: 'xx'
    //     })
    // }
    // test()



    // 初始化函数
    const init = () => {
        const t1 = new Date().getTime()
        isLoding.value = true
        const list = getData()
        // 在图片都加载完之后再进行排列
        handle(list).finally(() => {
            waterfalll(list)

            // 至少1s后关闭弹框
            const t2 = new Date().getTime()
            const time = 1000 - (t2 - t1)
            if (time > 0){
                setTimeout(() => {
                    isLoding.value = false
                }, time)
            }else{
                isLoding.value = false
            }
               

        })
    }
    init()

    // 监听Y轴页面滚动
    watch(y, (newValue, oldValue) => {

        //判断当前滚动位置  + 容器 和浏览器显示高度的大小
        if (Math.ceil(newValue) + Math.ceil(document.documentElement.clientHeight) >= Math.round(document.body
                .scrollHeight)) {
            init()
        }
    });

    // 重置渲染数据
    const reSetData = () => {
        // 重置数据
        loadedCount = 0
        total = 0
        colsHeightArr = []
        imgBoxList = []
        imgList.length = 0
        imgList.splice(0, imgList.length)
        beginIndex = 0
    }

    // 监听列变化
    watch(() => props.colNum, (value) => {
        reSetData()
        init()
    })
    watch(() => props.colInterval, (value) => {
        reSetData()
        init()
    })
</script>
<style lang="scss" scoped>
    .app-container {
        display: flex;
        width: 100%;
        justify-content: center;

        .container {
            width: v-bind(waterfallWidthPx);
            display: flex;
            flex-wrap: wrap;
            position: relative;

            .item {
                position: absolute;
                width: v-bind(colWidthPx);
                border-radius: 10px;
                overflow: hidden;

                img {
                    width: 100%;
                    height: 100%;
                }

            }

            .loding {
                width: 100%;
                height: 200px;
                background: red;
                position: absolute;
                bottom: -200;
                z-index: 100;
            }
        }
    }
</style>